import logging
import os
import sys
import json
from tools import tools
from resources import (
    resources,
    server_info,
    sample_data,
    templates,
    meeting_notes_template,
    project_plan_template,
)
from prompts import prompts
from dotenv import load_dotenv
from datetime import datetime

load_dotenv()


def setup_logging():
    """设置日志配置"""
    log_level = os.getenv("LOG_LEVEL", "INFO").upper()
    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    )
    # 创建控制台日志处理器，输出到标准错误
    console_handler = logging.StreamHandler(sys.stderr)
    console_handler.setFormatter(formatter)
    # 配置日志记录器
    logging.basicConfig(
        level=getattr(logging, log_level),
        handlers=[console_handler],
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    )
    return logging.getLogger(__name__)


logger = setup_logging()


class MCPServer:
    def __init__(self):
        self.server_info = {"name": "MCPServer", "version": "1.0.0"}
        self.initialized = False
        self.tools = tools
        self.resources = resources
        self.templates = templates
        self.prompts = prompts

    def initialize(self):
        return {
            "protocolVersion": "2025-06-18",
            "capabilities": {
                "tools": {"listChanged": True},
                "resources": {"subscribe": True, "listChanged": True},
                "prompts": {"listChanged": True},
                "elicitation": {},
            },
            "serverInfo": {
                "name": "MCP Server",
                "title": "MCP Serve Display Name",
                "version": "1.0.0",
            },
            "resourceTemplates": list(self.templates.values()),
        }

    def handle_notification(self, method):
        if method == "notifications/initialized":
            self.initialized = True
            logger.info("initialized successfully")
        return None

    def _handle_ping(self, request_id):
        return {"jsonrpc": "2.0", "id": request_id, "result": {}}

    def _handle_list_tools(self, request_id):
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {"tools": list(self.tools.values())},
        }

    def _handle_get_time(self, arguments):
        format_type = arguments.get("format", "readable")
        now = datetime.now()
        if format_type == "iso":
            result = now.isoformat()
        elif format_type == "timestamp":
            result = now.timestamp()
        else:
            result = now.strftime("%Y-%m-%d %H:%M:%S")
        return [{"type": "text", "text": f"Current Time:{result}"}]

    def _handle_calculate(self, arguments):
        expression = arguments.get("expression", "")
        try:
            result = eval(expression)
            return [
                {"type": "text", "text": f"expression {expression} result is {result}"}
            ]
        except Exception as e:
            return [{"type": "text", "text": f"calculation failed:{str(e)}"}]

    def _handle_echo(self, arguments):
        message = arguments.get("message", "")
        return [{"type": "text", "text": f"Echo:{message}"}]

    def _handle_call_tool(self, request_id, params):
        name = params.get("name")
        arguments = params.get("arguments", {})
        try:
            logger.info(f"tool call:{name} with arguments:{arguments}")
            if name == "get_current_time":
                result = self._handle_get_time(arguments)
            elif name == "calculate":
                result = self._handle_calculate(arguments)
            elif name == "echo":
                result = self._handle_echo(arguments)
            else:
                logger.warning(f"unknown tool requests:{name}")
                return {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {
                        "code": -32607,
                        "message": f"unknown tool requests:{name}",
                    },
                }
            logger.info(f"tool {name} executed successfully")
            return {"jsonrpc": "2.0", "id": request_id, "result": {"content": result}}
        except Exception as e:
            logger.error(f"tool {name} call failed:{str(e)}")
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {
                    "code": -32608,
                    "message": f"tool {name} call failed:{str(e)}",
                },
            }

    def _handle_resource_list(self, request_id):
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {"resources": list(self.resources.values())},
        }

    def _handle_read_resource(self, request_id, params):
        uri = params.get("uri")
        if uri == "mcp://server-info":
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "contents": [
                        {
                            "uri": "mcp://server-info",
                            "name": "Server Information",
                            "description": "Basic information about current server",
                            "mimeType": "application/json",
                            "text": json.dumps(server_info, indent=2),
                        }
                    ]
                },
            }
        elif uri == "mcp://sample-data":
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "contents": [
                        {
                            "uri": "mcp://sample-data",
                            "name": "Sample Data",
                            "description": "Some sample JSON data",
                            "mimeType": "application/json",
                            "text": json.dumps(sample_data, indent=2),
                        }
                    ]
                },
            }
        else:
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {"code": -32601, "message": "resource {uri} not found"},
            }

    def _handle_resource_templates_list(self, request_id):
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {"resourceTemplates": list(self.templates.values())},
        }

    def _handle_read_template_resource(self, request_id, params):
        uri = params.get("uri")
        if uri == "mcp://templates/project-plan":
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "contents": [
                        {
                            "uri": "mcp://templates/project-plan",
                            "uriTemplate": "mcp://templates/project-plan",
                            "name": "Project Plan Template",
                            "description": "Template for creating project plans",
                            "mimeType": "application/json",
                            "text": json.dumps(project_plan_template, indent=2),
                        }
                    ]
                },
            }
        elif uri == "mcp://templates/meeting-notes":
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "contents": [
                        {
                            "uri": "mcp://templates/meeting-notes",
                            "uriTemplate": "mcp://templates/meeting-notes",
                            "name": "Meeting Notes Template",
                            "description": "Template for meeting notes",
                            "mimeType": "application/json",
                            "text": json.dumps(meeting_notes_template, indent=2),
                        }
                    ]
                },
            }
        else:
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {"code": -32601, "message": "resource {uri} not found"},
            }

    def _handle_prompts_list(self, request_id):
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {"prompts": list(self.prompts.values())},
        }

    def _handle_greeting_prompt(self, arguments):
        name = arguments.get("name", "User")
        time_of_day = arguments.get("time_of_day", "day")
        greetings = {
            "morning": "Good Morning",
            "afternoon": "Good afternoon",
            "evening": "Good evening",
            "night": "Good night",
        }
        greeting = greetings.get(time_of_day, "Hello")
        content = f"{greeting},{name}! welcome to the mcp server"
        return [
            {
                "role": "assistant",
                "content": {
                    "type": "text",
                    "text": content,
                },
            }
        ]

    def _handle_status_report_prompt(self, arguments):
        project = arguments.get("project", "Unknown project")
        status = arguments.get("status", "Unknown")
        status_message = {
            "on_track": "project is on track",
            "at_risk": "Project is at risk",
            "behind_schedule": "Project is behind schedule",
        }
        message = status_message.get(status, "Unknown Status")
        content = f"Project {project} status report: {message}"
        return [
            {
                "role": "assistant",
                "content": {
                    "type": "text",
                    "text": content,
                },
            }
        ]

    def _handle_read_prompt(self, request_id, params):
        name = params.get("name")
        arguments = params.get("arguments")
        try:
            if name == "greeting":
                result = self._handle_greeting_prompt(arguments)
            elif name == "status_report":
                result = self._handle_status_report_prompt(arguments)
            else:
                return {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {
                        "code": -32601,
                        "message": f"Unknown prompt: {name}",
                    },
                }
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {"description": name, "messages": result},
            }
        except Exception as e:
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {"code": -32601, "message": f"get prompt failed. :{str(e)}"},
            }

    def _handle_mcp_sampling(self, request_id, params):
        try:
            logger.info("收到客户端的演示采样请求")
            sampling_request = {
                "jsonrpc": "2.0",
                "id": f"mcp_sampling_{request_id}",
                "method": "sampling/createMessage",
                "params": {
                    "messages": [
                        {
                            "role": "user",
                            "content": {
                                "type": "text",
                                "text": "What is the capital of France?",
                            },
                        }
                    ],
                    "modelPreferences": {
                        "hints": [{"name": "gpt-4"}],
                        "intelligencePriority": 0.8,  # 越小越不关心智能
                        "speedPriority": 0.5,  #  越小越不关心速度
                        "costPriority": 0.3,  # 越小越不关心成本
                    },
                    "systemPrompt": "You are a helpful assistant.",  # 系统提示词
                    "maxTokens": 1024,  # 最大token
                },
            }
            logger.info(f"已经把采样请求发给客户端")
            return sampling_request
        except Exception as e:
            logger.error(f"mcp sampling failed:{str(e)}")
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {"code": -32601, "message": f"mcp sampling failed:{str(e)}"},
            }

    def _handle_mcp_elicitation(self, request_id, params):
        try:
            logger.info("收到客户端的触发启发的引导请求")
            elicitation_request = {
                "jsonrpc": "2.0",
                "id": f"mcp_elicitation_{request_id}",
                "method": "elicitation/create",
                "params": {
                    "message": "please provide you preference for the project configuration",
                    "requestedSchema": {
                        "type": "object",
                        "properties": {
                            "username": {"type": "string", "description": "Your name"},
                            "preference": {
                                "type": "string",
                                "description": "Your preferred style",
                                "enum": ["creative", "analytical", "practical"],
                            },
                        },
                        "required": ["name"],
                    },
                },
            }
            # 发请引导请求到服务器端
            request_str = json.dumps(elicitation_request, ensure_ascii=False)
            print(request_str)
            sys.stdout.flush()
            logger.info("已发送启动引导给客户端")
            return elicitation_request
        except Exception as e:
            pass

    def handle_request(self, request):
        method = request.get("method")
        request_id = request.get("id", 0)
        params = request.get("params", {})
        try:
            if "id" not in request:
                return self.handle_notification(method)
            if method == "initialize":
                result = self.initialize()
                return {"jsonrpc": "2.0", "id": request_id, "result": result}
            elif method == "ping":
                return self._handle_ping(request_id)
            elif method == "tools/list":
                return self._handle_list_tools(request_id)
            elif method == "tools/call":
                return self._handle_call_tool(request_id, params)
            elif method == "resources/list":
                return self._handle_resource_list(request_id)
            elif method == "resources/read":
                return self._handle_read_resource(request_id, params)
            elif method == "resources/templates/list":
                return self._handle_resource_templates_list(request_id)
            elif method == "resources/templates/read":
                return self._handle_read_template_resource(request_id, params)
            elif method == "prompts/list":
                return self._handle_prompts_list(request_id)
            elif method == "prompts/get":
                return self._handle_read_prompt(request_id, params)
            elif method == "mcp/sampling":
                return self._handle_mcp_sampling(request_id, params)
            elif method == "sampling/result":
                logger.info(f"method:{method}")
                return {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "result": "你的采样结果我已经收到，很满意 ，谢谢",
                }
            elif method == "mcp/elicitation":
                return self._handle_mcp_elicitation(request_id, params)
            else:
                return {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {"code": -32601, "message": "method {method} not found"},
                }

        except Exception as e:
            logger.error(f"request handle error:{str(e)}")
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {"code": -32603, "message": f"Server internal error:{str(e)}"},
            }


import time


def auto_elicitation_request():
    def send_elicitation_request():
        time.sleep(5)
        elicitation_request = {
            "jsonrpc": "2.0",
            "id": f"mcp_elicitation_001",
            "method": "elicitation/create",
            "params": {
                "message": "please provide you preference for the project configuration",
                "requestedSchema": {
                    "type": "object",
                    "properties": {
                        "username": {"type": "string", "description": "Your name"},
                        "preference": {
                            "type": "string",
                            "description": "Your preferred style",
                            "enum": ["creative", "analytical", "practical"],
                        },
                    },
                    "required": ["message", "preference"],
                },
            },
        }
        request_str = json.dumps(elicitation_request, ensure_ascii=False)
        print(request_str)
        sys.stdout.flush()

    import threading

    ## 开始一个自动引导线程
    auto_thread = threading.Thread(target=send_elicitation_request, daemon=True)
    auto_thread.start()


def auto_sampling_request():
    def send_sampling_request():
        time.sleep(5)
        sampling_request = {
            "jsonrpc": "2.0",
            "id": f"mcp_sampling_001",
            "method": "sampling/createMessage",
            "params": {
                "messages": [
                    {
                        "role": "user",
                        "content": {
                            "type": "text",
                            "text": "What is the capital of France?",
                        },
                    }
                ],
                "modelPreferences": {
                    "hints": [{"name": "gpt-4"}],
                    "intelligencePriority": 0.8,  # 越小越不关心智能
                    "speedPriority": 0.5,  #  越小越不关心速度
                    "costPriority": 0.3,  # 越小越不关心成本
                },
                "systemPrompt": "You are a helpful assistant.",  # 系统提示词
                "maxTokens": 1024,  # 最大token
            },
        }
        request_str = json.dumps(sampling_request, ensure_ascii=False)
        print(request_str)
        sys.stdout.flush()

    import threading

    ## 开始一个自动引导线程
    auto_thread = threading.Thread(target=send_sampling_request, daemon=True)
    auto_thread.start()


def main():
    logging.info("Starting server...")
    mcp_server = MCPServer()
    # auto_elicitation_request()
    auto_sampling_request()
    try:
        # 监听用户输入也就是循环读取标准输入每一行
        for line in sys.stdin:
            if not line.strip():
                continue
            try:
                #  解析JSON请求
                request = json.loads(line.strip())
                response = mcp_server.handle_request(request)
                # 如果获得了响应，就写入到服务器进程的标准输出里，相关于把消息发给了客户端
                if response is not None:
                    print(json.dumps(response, ensure_ascii=False))
                    sys.stdout.flush()
            except Exception as e:
                logger.error(f"Unknown error:{str(e)}")
    except KeyboardInterrupt:
        # 捕获键盘中断，记录错误日志
        logger.info("Server stopped")
    except Exception as e:
        logger.error(f"server error:{str(e)}")
        sys.exit(1)


if __name__ == "__main__":
    main()
